package modules

import (
	"fmt"
	"github.com/goccy/go-json"
	"github.com/gorilla/websocket"
	"gopkg.in/fatih/set.v0"
	"gorm.io/gorm"
	"net"
	"net/http"
	"strconv"
	"sync"
)

type Message struct {
	gorm.Model
	FormID      int64  //发送
	TargetId    int64  //接收
	Type        int    //消息类型 群聊 私聊 广播
	Media       int    //消息类型 文字 图片 音频
	Content     string //消息内容
	Picture     string
	Url         string
	Description string
	Amount      int //其他数字统计
}

func (table *Message) TableName() string {
	return "Message"
}

type Node struct {
	Conn      *websocket.Conn
	DataQueue chan []byte
	GroupSets set.Interface
}

var clientMap map[int64]*Node = make(map[int64]*Node, 0)

var rwLocker sync.RWMutex

func Chat(writer http.ResponseWriter, request *http.Request) {
	// 获取参数校验合法性
	query := request.URL.Query()
	id := query.Get("userId")
	userId, _ := strconv.ParseInt(id, 10, 64)
	//msgType := query.Get("msgType")
	//targetId := query.Get("targetId")
	//context := query.Get("context")
	isvalid := true
	conn, err := (&websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return isvalid
		},
	}).Upgrade(writer, request, nil)
	if err != nil {
		fmt.Print(err)
		return
	}
	// 获取连接
	node := &Node{
		Conn:      conn,
		DataQueue: make(chan []byte, 50),
		GroupSets: set.New(set.ThreadSafe),
	}
	// userId 与node绑定并加锁
	rwLocker.Lock()
	clientMap[userId] = node
	rwLocker.Unlock()

	// 发送逻辑
	go sendProc(node)

	// 完成逻辑
	go recvProc(node)

	sendMsg(userId, []byte("Welcome!"))
}

func recvProc(node *Node) {
	for {
		select {
		case data := <-node.DataQueue:
			err := node.Conn.WriteMessage(websocket.TextMessage, data)
			if err != nil {
				fmt.Println(err)
				return
			}
		}
	}
}

func sendProc(node *Node) {
	for {
		_, message, err := node.Conn.ReadMessage()
		if err != nil {
			fmt.Println(err)
			return
		}
		broadMsg(message)
		fmt.Println("[message] <<<<", string(message))
	}
}

var udpSendChan chan []byte = make(chan []byte, 1024)

func broadMsg(message []byte) {
	udpSendChan <- message
}

func init() {
	go udpSendProc()
	go udpRecvProc()
}

// UDP数据发送协程
func udpSendProc() {
	con, err := net.DialUDP("udp", nil, &net.UDPAddr{
		IP:   net.IPv4(192, 168, 0, 255),
		Port: 3000,
	})
	defer func(con *net.UDPConn) {
		err := con.Close()
		if err != nil {
			fmt.Println(err)
		}
	}(con)
	if err != nil {
		fmt.Println(err)
	}
	for {
		select {
		case data := <-udpSendChan:
			_, err := con.Write(data)
			if err != nil {
				fmt.Println(err)
				return
			}
		}
	}
}

// UDP数据接收协程
func udpRecvProc() {
	con, err := net.ListenUDP("udp", &net.UDPAddr{
		IP:   net.IPv4zero,
		Port: 3000,
	})
	if err != nil {
		fmt.Println(err)
	}
	defer func(con *net.UDPConn) {
		err := con.Close()
		if err != nil {
			fmt.Println(err)
		}
	}(con)
	for {
		var buf [1024]byte
		n, err := con.Read(buf[0:])
		if err != nil {
			fmt.Println(err)
			return
		}
		dispatch(buf[0:n])
	}
}

// 后端调度逻辑
func dispatch(data []byte) {
	message := Message{}
	err := json.Unmarshal(data, &message)
	if err != nil {
		fmt.Println(err)
		return
	}
	switch message.Type {
	case 1:
		sendMsg(message.TargetId, data)
		//case 2:
		//	sendGroupMsg()
		//case 3:
		//	sendAllMsg()
	}
}

func sendMsg(userId int64, msg []byte) {
	rwLocker.RLock()
	node, ok := clientMap[userId]
	rwLocker.RUnlock()
	if !ok {
		node.DataQueue <- msg
	}
}
